package com.zfzs.post.service;

import cn.hutool.json.JSONObject;
import com.zfzs.post.common.bean.CommonConst;
import com.zfzs.post.common.bean.ResponseCode;
import com.zfzs.post.common.security.JwtUser;
import com.zfzs.post.common.utils.JwtTokenUtil;
import com.zfzs.post.exception.BadRequestException;
import com.zfzs.post.modules.agent.domain.Agent;
import com.zfzs.post.modules.agent.service.AgentService;
import com.zfzs.post.modules.agent.service.dto.AgentDTO;
import com.zfzs.post.modules.agent.service.mapper.AgentMapper;
import com.zfzs.post.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;

/**
 * 身份令牌
 * @author ck
 * @date 2018-11-22
 */
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class JwtUserDetailsService implements UserDetailsService {

    @Autowired
    private AgentService agentService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private AgentMapper agentMapper;

    @Value("${jwt.header}")
    private String tokenHeader;

    @Value("${jwt.expired.login}")
    private Long expiredLogin;

    private final String cacheKey = CommonConst.CACHE_LOGIN+CommonConst.APP;

    @Override
    public UserDetails loadUserByUsername(String username) {
        Agent agent = agentService.findById(Long.valueOf(username));
        if (agent == null) {
            throw new BadRequestException(ResponseCode.NO_USER_FAIL);
        } else {
            return createJwtUser(agentMapper.toDto(agent));
        }
    }

    /**
     * 得到头信息token
     * @param request
     * @return
     */

    public String getToken(HttpServletRequest request){
        final String requestHeader = request.getHeader(this.tokenHeader);
        String token = requestHeader.substring(7);
        return token;
    }

    /**
     * 清除token
     * @param token
     */
    public void clearToken(String token){
        if(!isToken(token)){
            throw new BadRequestException(ResponseCode.LOGIN_TIME_OUT_FAIL);
        }
        String key = cacheKey + token;
        redisService.delete(key);
    }

    /**
     * 判断token是否存在
     * @param token
     * @return
     */
    public boolean isToken(String token){
        String key = cacheKey+token;
        boolean isCache = redisService.hasKey(key);
        if (!isCache) {
            return false;
        }else{
            return true;
        }
    }
    /**
     * 生成TOKEN
     * @param id 用户ID主键
     */
    public String generateToken(Long id) {
        final JwtUser jwtUser = (JwtUser) loadUserByUsername(String.valueOf(id));
        final String token = jwtTokenUtil.generateJWTToken(jwtUser);
        //存入redis
        String key = CommonConst.CACHE_LOGIN+CommonConst.APP+token;
        boolean isToken = redisService.set(key, String.valueOf(id),expiredLogin);
        if(!isToken){
            throw new BadRequestException("登录失败");
        }
        return token;
    }

    /**
     * 得到缓存的token内容
     * @param token
     * @return
     */
    public Long getId(String token){
        if(!isToken(token)){
            throw new BadRequestException(ResponseCode.LOGIN_TIME_OUT_FAIL);
        }
        String key = cacheKey+token;
        String agentId = redisService.get(key);
        Long id = Long.valueOf(agentId).longValue();
        return id;
    }

    /**
     * 刷新TOKEN
     * @param token
     * @return
     */
    public String updateToken(String token) {
        //清除缓存
        Long id = getId(token);
        clearToken(token);
        String newToken = generateToken(id);
        return newToken;
    }

    /**
     * 获取登录人全部用户信息
     * @return
     */
    public static AgentDTO getAgentInfo(){
        Object obj = SecurityUtils.getUserDetails();
        JSONObject json = new JSONObject(obj);
        return json.get("agent", AgentDTO.class);
    }

    public UserDetails createJwtUser(AgentDTO user) {
        return new JwtUser(
                user.getId(),
                user.getChannelId(),
                null,
                user.getPassword(),
                null,
                user.getIsEnabled(),
                user.getCreateTime(),
                user.getUpdatePasswordTime(),
                user
        );
    }
}
